﻿using System;
using System.Globalization;
using System.Numerics;
using System.Text;
using ParserGenerator.Extensions;
using ParserGenerator.Output;

namespace ParserGenerator.Languages.MSIL
{
    partial class SyntaxTreeNodeWriter
    {
        public virtual void WriteIdentifier(Identifier n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            // TODO: escape
            writer.Write(n.Name, writer);
        }

        public virtual void WriteTypedefAliasType(TypedefAliasType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDottedName(n.Name, writer);
        }

        public virtual void WriteTypedefAliasClassName(TypedefAliasClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDottedName(n.Name, writer);
        }

        public virtual string EscapeCharacter(int c, char delimiter)
        {
            if (c < CharExtensions.MinChar || c > CharExtensions.MaxChar)
                throw new ArgumentOutOfRangeException(nameof(c), SR.InvalidUnicodeCodepoint);
            if (delimiter != '\'' && delimiter != '"')
                throw new ArgumentException(SR.DelimiterMustBeSingleOrDoubleQuote, nameof(delimiter));
            switch (c)
            {
                case '\0': return "\\0";
                case '\a': return "\\a";
                case '\b': return "\\b";
                case '\t': return "\\t";
                case '\n': return "\\n";
                case '\v': return "\\v";
                case '\f': return "\\f";
                case '\r': return "\\r";
                case '\\': return "\\\\";
                case '\'': return delimiter == '\'' ? "\\'" : "'";
                case '"': return delimiter == '"' ? "\\\"" : "\"";
                default:
                    if (' ' <= c && c <= 0x7E)
                        return "" + (char)c;
                    else if (0 <= c && c <= 0xFFFF)
                        return string.Format("\\u{0:X4}", c);
                    else
                        return string.Format("\\U{0:X8}", c);
            }
        }

        public virtual string FormatSingleQuoteLiteral(SingleQuoteLiteral n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            const char delimiter = '\'';
            StringBuilder sb = new StringBuilder();
            sb.Append(delimiter);
            foreach (int c in n.Value.EnumCodepoints())
            {
                string str = EscapeCharacter(c, delimiter);
                sb.Append(str);
            }
            sb.Append(delimiter);
            return sb.ToString();
        }

        public virtual void WriteSingleQuoteLiteral(SingleQuoteLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            string str = FormatSingleQuoteLiteral(n);
            writer.Write(str);
        }

        public virtual string FormatDoubleQuoteLiteral(DoubleQuoteLiteral n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            const char delimiter = '"';
            StringBuilder sb = new StringBuilder();
            sb.Append(delimiter);
            foreach (int c in n.Value.EnumCodepoints())
            {
                string str = EscapeCharacter(c, delimiter);
                sb.Append(str);
            }
            sb.Append(delimiter);
            return sb.ToString();
        }

        public virtual void WriteDoubleQuoteLiteral(DoubleQuoteLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            string str = FormatDoubleQuoteLiteral(n);
            writer.Write(str);
        }

        public virtual void WriteCompoundQuoteLiteral(CompoundQuoteLiteral n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(" + ");
                WriteDoubleQuoteLiteral(n.Items[i], writer);
            }
        }

        public virtual string FormatInt32Literal(Int32Literal n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            bool isHex = n.IsHexadecimal ?? false;
            long v = n.Value;
            StringBuilder sb = new StringBuilder();
            if (v < 0)
            {
                sb.Append("-");
                v = -v;
            }
            if (isHex)
            {
                string str = v.ToString("x", CultureInfo.InvariantCulture);
                str = str.TrimStart('0');
                if (str.Length == 0)
                    str = "0";
                sb.Append("0x");
                sb.Append(str);
            }
            else
            {
                string str = v.ToString(CultureInfo.InvariantCulture);
                sb.Append(str);
            }
            return sb.ToString();
        }

        public virtual void WriteInt32Literal(Int32Literal n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            string str = FormatInt32Literal(n);
            writer.Write(str);
        }

        public virtual string FormatInt64Literal(Int64Literal n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            bool isHex = n.IsHexadecimal ?? false;
            BigInteger v = n.Value;
            StringBuilder sb = new StringBuilder();
            if (v < 0)
            {
                sb.Append("-");
                v = -v;
            }
            if (isHex)
            {
                string str = v.ToString("x", CultureInfo.InvariantCulture);
                str = str.TrimStart('0');
                if (str.Length == 0)
                    str = "0";
                sb.Append("0x");
                sb.Append(str);
            }
            else
            {
                string str = v.ToString(CultureInfo.InvariantCulture);
                sb.Append(str);
            }
            return sb.ToString();
        }

        public virtual void WriteInt64Literal(Int64Literal n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            string str = FormatInt64Literal(n);
            writer.Write(str);
        }

        public virtual string FormatNonNegativeInt32Literal(NonNegativeInt32Literal n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            bool isHex = n.IsHexadecimal ?? false;
            int v = n.Value;
            StringBuilder sb = new StringBuilder();
            if (isHex)
            {
                string str = v.ToString("x", CultureInfo.InvariantCulture);
                str = str.TrimStart('0');
                if (str.Length == 0)
                    str = "0";
                sb.Append("0x");
                sb.Append(str);
            }
            else
            {
                string str = v.ToString(CultureInfo.InvariantCulture);
                sb.Append(str);
            }
            return sb.ToString();
        }

        public virtual void WriteNonNegativeInt32Literal(NonNegativeInt32Literal n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            string str = FormatNonNegativeInt32Literal(n);
            writer.Write(str);
        }

        public virtual void WriteMetadataToken(MetadataToken n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("mdtoken(");
            WriteInt32Literal(n.Value, writer);
            writer.Write(")");
        }

        public virtual void WriteIdentifierName(IdentifierName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteIdentifier(n.Name, writer);
        }

        public virtual void WriteSingleQuoteLiteralName(SingleQuoteLiteralName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteSingleQuoteLiteral(n.Name, writer);
        }

        public virtual void WriteSimpleDottedName(SimpleDottedName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteName(n.Name, writer);
        }

        public virtual void WriteCompoundDottedName(CompoundDottedName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDottedName(n.Operand, writer);
            writer.Write(".");
            WriteName(n.Member, writer);
        }

        public virtual void WriteSimpleSlashedName(SimpleSlashedName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteDottedName(n.Name, writer);
        }

        public virtual void WriteCompoundSlashedName(CompoundSlashedName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteSlashedName(n.Operand, writer);
            writer.Write("/");
            WriteDottedName(n.Member, writer);
        }

        public virtual void WriteDottedAssemblyClassName(DottedAssemblyClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteDottedName(n.Assembly, writer);
            writer.Write("]");
            WriteSlashedName(n.Name, writer);
        }

        public virtual void WriteMetadataTokenAssemblyClassName(MetadataTokenAssemblyClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteMetadataToken(n.Assembly, writer);
            writer.Write("]");
            WriteSlashedName(n.Name, writer);
        }

        public virtual void WriteStarAssemblyClassName(StarAssemblyClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[*]");
            WriteSlashedName(n.Name, writer);
        }

        public virtual void WriteDottedModuleClassName(DottedModuleClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[.module ");
            WriteDottedName(n.Module, writer);
            writer.Write("]");
            WriteSlashedName(n.Name, writer);
        }

        public virtual void WriteSlashedNameClassName(SlashedNameClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteSlashedName(n.Name, writer);
        }

        public virtual void WriteMetadataTokenClassName(MetadataTokenClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteMetadataToken(n.Token, writer);
        }

        public virtual void WriteTypedefAliasClassNameClassName(TypedefAliasClassNameClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypedefAliasClassName(n.Name, writer);
        }

        public virtual void WriteThisClassName(ThisClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(".this");
        }

        public virtual void WriteBaseClassName(BaseClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(".base");
        }

        public virtual void WriteNesterClassName(NesterClassName n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write(".nester");
        }

        public virtual void WriteNamedClassType(NamedClassType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("class ");
            WriteClassName(n.Name, writer);
        }

        public virtual void WriteNamedValueClassType(NamedValueClassType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("value class ");
            WriteClassName(n.Name, writer);
        }

        public virtual void WriteNamedValuetypeType(NamedValuetypeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("valuetype ");
            WriteClassName(n.Name, writer);
        }

        public virtual void WriteNumericTypeParameterReferenceType(NumericTypeParameterReferenceType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("!");
            WriteNonNegativeInt32Literal(n.Number, writer);
        }

        public virtual void WriteNumericMethodTypeParameterReferenceType(NumericMethodTypeParameterReferenceType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("!!");
            WriteNonNegativeInt32Literal(n.Number, writer);
        }

        public virtual void WriteNamedTypeParameterReferenceType(NamedTypeParameterReferenceType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("!");
            WriteDottedName(n.Name, writer);
        }

        public virtual void WriteNamedMethodTypeParameterReferenceType(NamedMethodTypeParameterReferenceType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("!!");
            WriteDottedName(n.Name, writer);
        }

        public virtual void WriteMethodPointerType(MethodPointerType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("method ");
            if (n.CallConvention != null)
            {
                WriteCallConvention(n.CallConvention, writer);
                writer.Write(" ");
            }
            WriteType(n.ReturnType, writer);
            writer.Write(" *(");
            if (n.FormalParameters != null)
                WriteFormalParameterList(n.FormalParameters, writer);
            writer.Write(")");
        }

        public virtual void WriteObjectType(ObjectType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("object");
        }

        public virtual void WriteTypedReferenceType(TypedReferenceType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("typedref");
        }

        public virtual void WriteStringType(StringType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("string");
        }

        public virtual void WriteVoidType(VoidType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("void");
        }

        public virtual void WriteCharType(CharType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("char");
        }

        public virtual void WriteBoolType(BoolType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bool");
        }

        public virtual void WriteInt8Type(Int8Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8");
        }

        public virtual void WriteInt16Type(Int16Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16");
        }

        public virtual void WriteInt32Type(Int32Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32");
        }

        public virtual void WriteInt64Type(Int64Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64");
        }

        public virtual void WriteFloat32Type(Float32Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32");
        }

        public virtual void WriteFloat64Type(Float64Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64");
        }

        public virtual void WriteUnsignedInt8Type(UnsignedInt8Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int8");
        }

        public virtual void WriteUnsignedInt16Type(UnsignedInt16Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int16");
        }

        public virtual void WriteUnsignedInt32Type(UnsignedInt32Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int32");
        }

        public virtual void WriteUnsignedInt64Type(UnsignedInt64Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int64");
        }

        public virtual void WriteUInt8Type(UInt8Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint8");
        }

        public virtual void WriteUInt16Type(UInt16Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint16");
        }

        public virtual void WriteUInt32Type(UInt32Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint32");
        }

        public virtual void WriteUInt64Type(UInt64Type n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint64");
        }

        public virtual void WriteNativeIntType(NativeIntType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("native int");
        }

        public virtual void WriteNativeUnsignedIntType(NativeUnsignedIntType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("native unsigned int");
        }

        public virtual void WriteNativeUIntType(NativeUIntType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("native uint");
        }

        public virtual void WriteNativeFloatType(NativeFloatType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("native float");
        }

        public virtual void WriteTypedefAliasTypeType(TypedefAliasTypeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypedefAliasType(n.Name, writer);
        }

        public virtual void WriteGenericInstantiationType(GenericInstantiationType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write("<");
            if (n.TypeArguments != null)
                WriteTypeArgumentList(n.TypeArguments, writer);
            writer.Write(">");
        }

        public virtual void WriteArrayType(ArrayType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write("[");
            if (n.Bounds != null)
                WriteArrayBounds(n.Bounds, writer);
            writer.Write("]");
        }

        public virtual void WriteFixedValuetypeArrayType(FixedValuetypeArrayType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write(" value [");
            WriteNonNegativeInt32Literal(n.Length, writer);
            writer.Write("]");
        }

        public virtual void WriteRequiredModifiedType(RequiredModifiedType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write(" modreq(");
            WriteClassName(n.Qualifier, writer);
            writer.Write(")");
        }

        public virtual void WriteOptionalModifiedType(OptionalModifiedType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write(" modopt(");
            WriteClassName(n.Qualifier, writer);
            writer.Write(")");
        }

        public virtual void WriteManagedPointerType(ManagedPointerType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write("&");
        }

        public virtual void WriteUnmanagedPointerType(UnmanagedPointerType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write("*");
        }

        public virtual void WritePinnedType(PinnedType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Operand, writer);
            writer.Write(" pinned");
        }

        public virtual void WriteArrayBounds(ArrayBounds n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Bounds.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteArrayBound(n.Bounds[i], writer);
            }
        }

        public virtual void WriteEllipsisArrayBound(EllipsisArrayBound n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("...");
        }

        public virtual void WriteFixedArrayBound(FixedArrayBound n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteNonNegativeInt32Literal(n.Length, writer);
        }

        public virtual void WriteLowerUpperArrayBound(LowerUpperArrayBound n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteInt32Literal(n.Lower, writer);
            writer.Write("...");
            WriteInt32Literal(n.Upper, writer);
        }

        public virtual void WriteLowerArrayBound(LowerArrayBound n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteInt32Literal(n.Lower, writer);
            writer.Write("...");
        }

        public virtual void WriteClassNameTypeSpecification(ClassNameTypeSpecification n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteClassName(n.Name, writer);
        }

        public virtual void WriteDottedNameTypeSpecification(DottedNameTypeSpecification n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteDottedName(n.Name, writer);
            writer.Write("]");
        }

        public virtual void WriteModuleDottedNameTypeSpecification(ModuleDottedNameTypeSpecification n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[.module ");
            WriteDottedName(n.Name, writer);
            writer.Write("]");
        }

        public virtual void WriteTypeTypeSpecification(TypeTypeSpecification n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteType(n.Type, writer);
        }

        public virtual void WriteQuadCustomNativeType(QuadCustomNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("custom(");
            WriteCompoundQuoteLiteral(n.Item1, writer);
            writer.Write(", ");
            WriteCompoundQuoteLiteral(n.Item2, writer);
            writer.Write(", ");
            WriteCompoundQuoteLiteral(n.Item3, writer);
            writer.Write(", ");
            WriteCompoundQuoteLiteral(n.Item4, writer);
            writer.Write(")");
        }

        public virtual void WriteCustomNativeType(CustomNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("custom(");
            WriteCompoundQuoteLiteral(n.Item1, writer);
            writer.Write(", ");
            WriteCompoundQuoteLiteral(n.Item2, writer);
            writer.Write(")");
        }

        public virtual void WriteVariantNativeType(VariantNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("variant");
        }

        public virtual void WriteCurrencyNativeType(CurrencyNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("currency");
        }

        public virtual void WriteSysCharNativeType(SysCharNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("syschar");
        }

        public virtual void WriteVoidNativeType(VoidNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("void");
        }

        public virtual void WriteBoolNativeType(BoolNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bool");
        }

        public virtual void WriteInt8NativeType(Int8NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8");
        }

        public virtual void WriteInt16NativeType(Int16NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16");
        }

        public virtual void WriteInt32NativeType(Int32NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32");
        }

        public virtual void WriteInt64NativeType(Int64NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64");
        }

        public virtual void WriteFloat32NativeType(Float32NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32");
        }

        public virtual void WriteFloat64NativeType(Float64NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64");
        }

        public virtual void WriteUnsignedInt8NativeType(UnsignedInt8NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int8");
        }

        public virtual void WriteUnsignedInt16NativeType(UnsignedInt16NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int16");
        }

        public virtual void WriteUnsignedInt32NativeType(UnsignedInt32NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int32");
        }

        public virtual void WriteUnsignedInt64NativeType(UnsignedInt64NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int64");
        }

        public virtual void WriteUInt8NativeType(UInt8NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint8");
        }

        public virtual void WriteUInt16NativeType(UInt16NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint16");
        }

        public virtual void WriteUInt32NativeType(UInt32NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint32");
        }

        public virtual void WriteUInt64NativeType(UInt64NativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint64");
        }

        public virtual void WriteErrorNativeType(ErrorNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("error");
        }

        public virtual void WriteDecimalNativeType(DecimalNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("decimal");
        }

        public virtual void WriteDateNativeType(DateNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("date");
        }

        public virtual void WriteBSTRNativeType(BSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bstr");
        }

        public virtual void WriteLPSTRNativeType(LPSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lpstr");
        }

        public virtual void WriteLPWSTRNativeType(LPWSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lpwstr");
        }

        public virtual void WriteLPTSTRNativeType(LPTSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lptstr");
        }

        public virtual void WriteObjectReferenceNativeType(ObjectReferenceNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("objectref");
        }

        public virtual void WriteIUnknownNativeType(IUnknownNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("iunknown");
            if (n.Index != null)
                WriteInterfaceIdParameterIndex(n.Index, writer);
        }

        public virtual void WriteIDispatchNativeType(IDispatchNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("idispatch");
            if (n.Index != null)
                WriteInterfaceIdParameterIndex(n.Index, writer);
        }

        public virtual void WriteStructNativeType(StructNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("struct");
        }

        public virtual void WriteInterfaceNativeType(InterfaceNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("interface");
            if (n.Index != null)
                WriteInterfaceIdParameterIndex(n.Index, writer);
        }

        public virtual void WriteSafeArrayNativeType(SafeArrayNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("safearray ");
            WriteVariantType(n.Element, writer);
            if (n.Descriptor != null)
            {
                writer.Write(", ");
                WriteCompoundQuoteLiteral(n.Descriptor, writer);
            }
        }

        public virtual void WriteIntNativeType(IntNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int");
        }

        public virtual void WriteUnsignedIntNativeType(UnsignedIntNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int");
        }

        public virtual void WriteUIntNativeType(UIntNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint");
        }

        public virtual void WriteNestedStructNativeType(NestedStructNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("nested struct");
        }

        public virtual void WriteByValStringNativeType(ByValStringNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("byvalstr");
        }

        public virtual void WriteAnsiBSTRNativeType(AnsiBSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("ansi bstr");
        }

        public virtual void WriteTBSTRNativeType(TBSTRNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("tbstr");
        }

        public virtual void WriteVariantBoolNativeType(VariantBoolNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("variant bool");
        }

        public virtual void WriteMethodNativeType(MethodNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("method");
        }

        public virtual void WriteAsAnyNativeType(AsAnyNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("as any");
        }

        public virtual void WriteLPStructNativeType(LPStructNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lpstruct");
        }

        public virtual void WriteTypedefAliasTypeNativeType(TypedefAliasTypeNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteTypedefAliasType(n.Name, writer);
        }

        public virtual void WritePointerNativeType(PointerNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteNativeType(n.Operand, writer);
            writer.Write("*");
        }

        public virtual void WriteArrayNativeType(ArrayNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteNativeType(n.Operand, writer);
            writer.Write("[");
            if (n.Length != null)
                WriteNonNegativeInt32Literal(n.Length, writer);
            if (n.Extra != null)
            {
                writer.Write("+");
                WriteNonNegativeInt32Literal(n.Extra, writer);
            }
            writer.Write("]");
        }

        public virtual void WriteFixedSysStringNativeType(FixedSysStringNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("fixed sysstring[");
            WriteNonNegativeInt32Literal(n.Length, writer);
            writer.Write("]");
        }

        public virtual void WriteFixedArrayNativeType(FixedArrayNativeType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("fixed array[");
            WriteNonNegativeInt32Literal(n.Length, writer);
            writer.Write("]");
            WriteNativeType(n.Operand, writer);
        }

        public virtual void WriteInterfaceIdParameterIndex(InterfaceIdParameterIndex n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("(iidparam=");
            WriteNonNegativeInt32Literal(n.Number, writer);
            writer.Write(")");
        }

        public virtual void WriteNullVariantType(NullVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("null");
        }

        public virtual void WriteVariantVariantType(VariantVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("variant");
        }

        public virtual void WriteCurrencyVariantType(CurrencyVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("currency");
        }

        public virtual void WriteVoidVariantType(VoidVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("void");
        }

        public virtual void WriteBoolVariantType(BoolVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bool");
        }

        public virtual void WriteInt8VariantType(Int8VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int8");
        }

        public virtual void WriteInt16VariantType(Int16VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int16");
        }

        public virtual void WriteInt32VariantType(Int32VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int32");
        }

        public virtual void WriteInt64VariantType(Int64VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int64");
        }

        public virtual void WriteFloat32VariantType(Float32VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float32");
        }

        public virtual void WriteFloat64VariantType(Float64VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("float64");
        }

        public virtual void WriteUnsignedInt8VariantType(UnsignedInt8VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int8");
        }

        public virtual void WriteUnsignedInt16VariantType(UnsignedInt16VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int16");
        }

        public virtual void WriteUnsignedInt32VariantType(UnsignedInt32VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int32");
        }

        public virtual void WriteUnsignedInt64VariantType(UnsignedInt64VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int64");
        }

        public virtual void WriteUInt8VariantType(UInt8VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint8");
        }

        public virtual void WriteUInt16VariantType(UInt16VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint16");
        }

        public virtual void WriteUInt32VariantType(UInt32VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint32");
        }

        public virtual void WriteUInt64VariantType(UInt64VariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint64");
        }

        public virtual void WritePointerVariantType(PointerVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("*");
        }

        public virtual void WriteDecimalVariantType(DecimalVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("decimal");
        }

        public virtual void WriteDateVariantType(DateVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("variant");
        }

        public virtual void WriteBSTRVariantType(BSTRVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("bstr");
        }

        public virtual void WriteLPSTRVariantType(LPSTRVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lpstr");
        }

        public virtual void WriteLPWSTRVariantType(LPWSTRVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("lpwstr");
        }

        public virtual void WriteIUnknownVariantType(IUnknownVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("iunknown");
        }

        public virtual void WriteIDispatchVariantType(IDispatchVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("idispatch");
        }

        public virtual void WriteSafeArrayVariantType(SafeArrayVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("safearray");
        }

        public virtual void WriteIntVariantType(IntVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("int");
        }

        public virtual void WriteUnsignedIntVariantType(UnsignedIntVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unsigned int");
        }

        public virtual void WriteUIntVariantType(UIntVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("uint");
        }

        public virtual void WriteErrorVariantType(ErrorVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("error");
        }

        public virtual void WriteHRESULTVariantType(HRESULTVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("hresult");
        }

        public virtual void WriteCArrayVariantType(CArrayVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("carray");
        }

        public virtual void WriteUserDefinedVariantType(UserDefinedVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("userdefined");
        }

        public virtual void WriteRecordVariantType(RecordVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("record");
        }

        public virtual void WriteFileTimeVariantType(FileTimeVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("filetime");
        }

        public virtual void WriteBlobVariantType(BlobVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("blob");
        }

        public virtual void WriteStreamVariantType(StreamVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("stream");
        }

        public virtual void WriteStorageVariantType(StorageVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("storage");
        }

        public virtual void WriteStreamedObjectVariantType(StreamedObjectVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("streamed_object");
        }

        public virtual void WriteStoredObjectVariantType(StoredObjectVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("stored_object");
        }

        public virtual void WriteBlobObjectVariantType(BlobObjectVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("blob_object");
        }

        public virtual void WriteClassFactoryVariantType(ClassFactoryVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("cf");
        }

        public virtual void WriteCLSIDVariantType(CLSIDVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("clsid");
        }

        public virtual void WriteArrayVariantType(ArrayVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteVariantType(n.Operand, writer);
            writer.Write("[]");
        }

        public virtual void WriteVectorVariantType(VectorVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteVariantType(n.Operand, writer);
            writer.Write(" vector");
        }

        public virtual void WriteReferenceVariantType(ReferenceVariantType n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            WriteVariantType(n.Operand, writer);
            writer.Write("&");
        }

        public virtual void WriteInstanceCallConvention(InstanceCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("instance");
            if (n.Operand != null)
            {
                writer.Write(" ");
                WriteCallConvention(n.Operand, writer);
            }
        }

        public virtual void WriteExplicitCallConvention(ExplicitCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("explicit");
            if (n.Operand != null)
            {
                writer.Write(" ");
                WriteCallConvention(n.Operand, writer);
            }
        }

        public virtual void WriteDefaultCallConvention(DefaultCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("default");
        }

        public virtual void WriteVarargCallConvention(VarargCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("vararg");
        }

        public virtual void WriteCdeclCallConvention(CdeclCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unmanaged cdecl");
        }

        public virtual void WriteStdcallCallConvention(StdcallCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unmanaged stdcall");
        }

        public virtual void WriteThisCallCallConvention(ThisCallCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unmanaged thiscall");
        }

        public virtual void WriteFastCallCallConvention(FastCallCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("unmanaged fastcall");
        }

        public virtual void WriteNumericCallConvention(NumericCallConvention n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("callconv(");
            WriteInt32Literal(n.Number, writer);
            writer.Write(")");
        }

        public virtual void WriteTypeArgumentList(TypeArgumentList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteType(n.Items[i], writer);
            }
        }

        public virtual void WriteFormalParameterList(FormalParameterList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            for (int i = 0; i < n.Items.Count; i++)
            {
                if (i > 0)
                    writer.Write(", ");
                WriteFormalParameter(n.Items[i], writer);
            }
        }

        public virtual void WriteEllipsisFormalParameter(EllipsisFormalParameter n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("...");
        }

        public virtual void WriteNormalFormalParameter(NormalFormalParameter n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            if (n.Attributes != null)
            {
                WriteFormalParameterAttributeList(n.Attributes, writer);
                writer.Write(" ");
            }
            WriteType(n.Type, writer);
            if (n.Marshal != null)
            {
                writer.Write(" ");
                WriteMarshalClause(n.Marshal, writer);
            }
            if (n.Name != null)
            {
                writer.Write(" ");
                WriteName(n.Name, writer);
            }
        }

        public virtual void WriteMarshalClause(MarshalClause n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("marshal(");
            WriteNativeType(n.Type, writer);
            writer.Write(")");
        }

        public virtual void WriteFormalParameterAttributeList(FormalParameterAttributeList n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            foreach (FormalParameterAttribute item in n.Items)
                WriteFormalParameterAttribute(item, writer);
        }

        public virtual void WriteInFormalParameterAttribute(InFormalParameterAttribute n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[in]");
        }

        public virtual void WriteOutFormalParameterAttribute(OutFormalParameterAttribute n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[out]");
        }

        public virtual void WriteOptionalFormalParameterAttribute(OptionalFormalParameterAttribute n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[opt]");
        }

        public virtual void WriteNumericFormalParameterAttribute(NumericFormalParameterAttribute n, IndentedWriter writer)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.Write("[");
            WriteInt32Literal(n.Number, writer);
            writer.Write("]");
        }
    }

    partial class MSILProgramParser
    {
        private void ScanIdentifierName()
        {
            string value = TokenContext.GetSource();
            TokenValue = Identifier.New(value, TokenContext);
        }

        private void ScanIntegerValue(bool negative, int radix)
        {
            string str = TokenContext.GetSource();
            int start = (radix == 10) ? 0 : 2;
            if (negative)
                start++;
            BigInteger v = 0;
            for (int i = start; i < str.Length; i++)
            {
                int d = str[i].ValueOfDigit();
                v = v * radix + d;
            }
            if (negative)
                v = -v;
            if (int.MinValue <= v && v <= int.MaxValue)
                TokenValue = Int32Literal.New((int)v, radix == 16, TokenContext);
            else if (long.MinValue <= v && v <= long.MaxValue)
                TokenValue = Int64Literal.New((long)v, radix == 16, TokenContext);
            else
                throw SyntaxError(SR.IntegerLiteralValueTooHugeToFitIntoInt64, TokenContext);
        }

        private NonNegativeInt32Literal CheckNonNegativeInt32Literal(Int32Literal n)
        {
            if (n == null)
                throw new ArgumentNullException(nameof(n));
            if (n.Value < 0)
                throw SyntaxError(SR.NonNegativeInt32LiteralExpected, n.Context);
            return NonNegativeInt32Literal.New(n.Value, n.IsHexadecimal, n.Context);
        }
    }
}
